/* 测试meta */

#include <dbg/ptest.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>


// #include <metalc/meta/pgmap.h>
#include <metalc/meta.h>
#include <page_alloc.h>



/* flatmap */
DEF_FLAT_EXT_MMETA(pgbyte, byte_t, HDEF_PTR_BITS, 16, page_alloc, page_free)

/* 1级radix 4KB大小, 2级 flatmap每个成员2^23 * 8字节 = 64MB */
DEF_L2_EXT_MMETA(size, size_t, HDEF_PTR_BITS, 16, page_alloc, page_free)

static void test_extmeta(){
	mmeta_init_pgbyte();
	void *ptr;
	fvoid *fptr; 
	byte_t *p;
	byte_t *f;
	p = mmeta_by_ptr_pgbyte(NULL, 0, sizeof(byte_t), &fptr);
	assert(p);
	*p = 5;
	f = mmeta_by_fptr_pgbyte(fptr, 0, &ptr);
	assert(f);
	assert(ptr == NULL);
	assert(*f == 5);

	/* 2级 */
	word_t size = rand()%4096;
	void *mem = (void *)malloc(size);
	size_t *pmeta2;
	size_t *pmeta = mmeta_by_ptr_size(mem, size, sizeof(size_t), &fptr);
	assert(pmeta);
	*pmeta = size;
	pmeta2 = mmeta_by_fptr_size(fptr, 0, &ptr);
	assert(pmeta2);
	assert(pmeta2 == pmeta);
	assert(ptr == mem);
	assert(*pmeta2 == size);
	free(mem);
}

DEF_MMETA_HD(hdw, size_t, sizeof(size_t))

DEF_MMETA_HD(hdw_vary, word_t, 0)

static void test_meta_hd(){
	mmeta_init_hdw();
	void *mem = (void *)malloc(sizeof(size_t) * 2);
	fvoid *fptr;
	void *ptr;
	assert(mem);
	size_t *psize = mmeta_by_ptr_hdw(mem, sizeof(size_t) * 2, sizeof(size_t), &fptr);
	assert((void *)psize == mem);
	assert((void *)fptr == (mem + sizeof(size_t)) );
	*psize = sizeof(size_t) * 2 - sizeof(size_t);
	psize = mmeta_by_fptr_hdw(fptr, 0, &ptr);
	assert(*psize == sizeof(size_t) * 2 - sizeof(size_t));
	assert(ptr == mem);
	free(mem);

	/* 不定长 */
	{
		size_t totalsize = sizeof(size_t) + mmeta_ocupysize_hdw_vary(6 * sizeof(size_t));
		void *mem = (void *)malloc(totalsize);
		assert(mem);
		fvoid *fptr;
		void *ptr;
		word_t testarr[] = {1, 2, 3 ,4 ,5 ,6};
		word_t *pmeta = mmeta_by_ptr_hdw_vary(mem, totalsize, 6 * sizeof(size_t), &fptr);
		assert((void *)pmeta == mem);
		assert((void *)fptr == mem + 7 * sizeof(size_t));
		assert(pmeta);
		/* 拷贝meta 信息*/
		__memcpy(pmeta, testarr, sizeof(word_t) * 6);

		pmeta = mmeta_by_fptr_hdw_vary(fptr, 0, &ptr);
		assert(__memcmp(pmeta, testarr, sizeof(word_t) * 6) == 0);
		assert(ptr == mem);

		free(mem);
	}
}

DEF_MMETA_TL(tlw, size_t, sizeof(size_t))
DEF_MMETA_TL(tlw_vary, word_t, 0)

/* 尾部 */
static void test_meta_tl(){
	mmeta_init_tlw();
	void *mem = (void *)malloc(sizeof(size_t) + mmeta_ocupysize_tlw(sizeof(size_t)));
	fvoid *fptr;
	void *ptr;
	assert(mem);
	size_t *psize = mmeta_by_ptr_tlw(mem, sizeof(size_t) + mmeta_ocupysize_tlw(sizeof(size_t)), sizeof(size_t), &fptr);
	assert((void *)fptr == (mem + sizeof(size_t)));
	*psize = sizeof(size_t);
	psize = mmeta_by_fptr_tlw(fptr, 0, &ptr);
	assert(*psize == sizeof(size_t));
	assert((void *)psize == (mem + 2 * sizeof(size_t)));
	assert(ptr == mem);
	free(mem);

	/* 不定长 */
	{
		size_t totalsize = sizeof(size_t) + mmeta_ocupysize_tlw_vary(6 * sizeof(size_t));
		void *mem = (void *)malloc(totalsize);
		assert(mem);
		fvoid *fptr;
		void *ptr;
		word_t testarr[] = {1, 2, 3 ,4 ,5 ,6};
		word_t *pmeta = mmeta_by_ptr_tlw_vary(mem, totalsize, 6 * sizeof(size_t), &fptr);
		assert((void *)fptr == mem + sizeof(size_t));
		assert(pmeta);
		assert((void *)pmeta == mem + 2 * sizeof(size_t));
		/* 拷贝meta 信息*/
		__memcpy(pmeta, testarr, sizeof(word_t) * 6);

		pmeta = mmeta_by_fptr_tlw_vary(fptr, 0, &ptr);
		assert(__memcmp(pmeta, testarr, sizeof(word_t) * 6) == 0);
		assert(ptr == mem);

		free(mem);
	}
}


int main(){
	test_extmeta();
	test_meta_hd();
	test_meta_tl();
	printf("all tests pass\n");
}